package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.IdAndNumDTO;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author 赵博凯
 * @since 2025-10-18
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    @Autowired
    private CourseClient courseClient;

    @Autowired
    private final CatalogueClient catalogueClient;

    @Autowired
    private LearningRecordMapper recordMapper;


    @Override
    @Transactional
    public void addLessons(Long userId, List<Long> courseIds) {
        // 1.根据课程ID集合 远程调用 查询课程信息（课程有效期）
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);
        if (ObjectUtil.isEmpty(courseInfoList) || courseInfoList.size() != courseIds.size()) {
            // 课程不存在，无法添加
            log.error("课程信息不存在，无法添加到课表");
            return;
        }
        // 2. 遍历课程集合 组装课表数据
        List<LearningLesson> lessons = new ArrayList<>(courseInfoList.size());
        for (CourseSimpleInfoDTO courseInfo : courseInfoList) {
            LearningLesson lesson = new LearningLesson();
            // 2.1.填充userId和courseId
            lesson.setUserId(userId);
            lesson.setCourseId(courseInfo.getId());

            // 2.2.填充课程过期时间
            Integer validDuration = courseInfo.getValidDuration();
            if (ObjectUtil.isEmpty(validDuration) || validDuration <= 0) {
                continue;
            }
            lesson.setExpireTime(LocalDateTime.now().plusMonths(validDuration));
            lessons.add(lesson);
        }
        // 3.批量插入
        this.saveBatch(lessons);
    }
    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        // 1. 获取当前登录用户
        Long userId = UserContext.getUser();

        // 2. 根据用户ID和课程ID查询课表信息
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();

        // 3. 如果课表中没有该课程，返回null
        if (lesson == null) {
            return null;
        }

        // 4. 拷贝基础属性到VO
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);

        // 5. 查询课程详细信息
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(courseId, false, false);
        if (courseInfo != null) {
            vo.setCourseName(courseInfo.getName());
            vo.setCourseCoverUrl(courseInfo.getCoverUrl());
            vo.setSections(courseInfo.getSectionNum());
        }

        // 6. 查询最新学习的小节信息
        if (lesson.getLatestSectionId() != null) {
            List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(
                    CollUtils.singletonList(lesson.getLatestSectionId()));
            if (!CollUtils.isEmpty(cataInfos)) {
                CataSimpleInfoDTO cataInfo = cataInfos.get(0);
                vo.setLatestSectionName(cataInfo.getName());
                vo.setLatestSectionIndex(cataInfo.getCIndex());
            }
        }

        return vo;
    }

    @Override
    public Long isLessonValid(Long courseId) {
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();

        return lesson != null ? lesson.getId() : null;
    }


    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery pageQuery) {
        //1、获取当前登录人
        Long userId = UserContext.getUser();

        //2、发起分页查询
       /* Page<LearningLesson> page = Page.of(pageQuery.getPageNo(), pageQuery.getPageSize());
        if (ObjectUtil.isEmpty(pageQuery.getSortBy())){
            page.addOrder(OrderItem.desc("latest_learn_time"));
        }else{
            page.addOrder(new OrderItem(pageQuery.getSortBy(), pageQuery.getIsAsc()));
        }*/

        Page<LearningLesson> pageResult = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = pageResult.getRecords();
        if(ObjectUtil.isEmpty(records)){
            return PageDTO.empty(pageResult);
        }


        //3、发起远程调用，查询课程信息（课程名称、封面、总课时数）
        Map<Long, CourseSimpleInfoDTO> courseInfoList = queryCourseInfoAnd2Map(records);

        //4、循环分页结果，将po、list转为 vo、list
        List<LearningLessonVO> voList = new ArrayList<>(records.size());
        for (LearningLesson lesson : records) {
            //4.1、拷贝po到vo
            LearningLessonVO vo = BeanUtils.toBean(lesson, LearningLessonVO.class);

            //4.2、获取课程特有信息（课程名称、封面、总课时数），填充至vo
            CourseSimpleInfoDTO course = courseInfoList.get(lesson.getCourseId());
            vo.setCourseName(course.getName());
            vo.setCourseCoverUrl(course.getCoverUrl());
            vo.setSections(course.getSectionNum());

            //4.3存入vo集合
            voList.add(vo);

        }


        //5、封装最终的pageDTO并返回
        return PageDTO.of(pageResult, voList);
    }

    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        // 1.获取当前登录的用户
        Long userId = UserContext.getUser();
        // 2.查询正在学习的课程 select * from xx where user_id = #{userId} AND status = 1 order by latest_learn_time limit 1
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (lesson == null) {
            return null;
        }
        // 3.拷贝PO基础属性到VO
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        // 4.查询课程信息
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cInfo == null) {
            throw new BadRequestException("课程不存在");
        }
        vo.setCourseName(cInfo.getName());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());

        // 5.设置学习计划信息
        vo.setWeekFreq(lesson.getWeekFreq());

        // 6.统计课表中的课程数量 select count(1) from xxx where user_id = #{userId}
        Integer courseAmount = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
        vo.setCourseAmount(courseAmount);
        // 7.查询小节信息
        List<CataSimpleInfoDTO> cataInfos =
                catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataInfos)) {
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            vo.setLatestSectionName(cataInfo.getName());
            vo.setLatestSectionIndex(cataInfo.getCIndex());
        }
        return vo;
    }

    @Override
    public LearningLesson queryByUserAndCourseId(Long userId, Long courseId) {
        return getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
    }

    // 新增重载方法，用于处理退款场景
    @Override
    @Transactional
    public void removeByUserAndCourseId(Long[] courseIds, boolean isRefund) {
        // 1. 获取当前登录用户
        Long userId = UserContext.getUser();

        // 2. 构造删除条件：根据用户ID和课程ID列表删除课表记录
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getCourseId, Arrays.asList(courseIds));

        // 3. 执行删除操作
        this.remove(queryWrapper);

        // 4. 根据不同场景处理后续逻辑
        if (isRefund) {
            // 场景2: 用户退款后触发课表自动删除
            log.info("因用户退款自动删除课程: userId={}, courseIds={}", userId, courseIds);
            // 可以发送消息通知其他服务课程已被删除
            // notifyOtherServicesForRefund(courseIds);
        } else {
            // 场景1: 用户直接删除已失效的课程
            log.info("用户主动删除课程: userId={}, courseIds={}", userId, courseIds);
            // 可以记录删除日志
            // recordDeletionLog(userId, courseIds);
        }
    }

    // 原有方法保持不变，调用新方法
    @Override
    @Transactional
    public void removeByUserAndCourseId(Long[] courseIds) {
        removeByUserAndCourseId(courseIds, false); // 默认为用户主动删除
    }





    @Override
    public void createLearningPlan(Long courseId, Integer freq) {
        // 1.获取当前登录的用户
        Long userId = UserContext.getUser();
        // 2.查询课表中的指定课程有关的数据
        LearningLesson lesson = queryByUserAndCourseId(userId, courseId);
        AssertUtils.isNotNull(lesson, "课程信息不存在！");
        // 3.修改数据
        LearningLesson l = new LearningLesson();
        l.setId(lesson.getId());
        l.setWeekFreq(freq);
        if(lesson.getPlanStatus() != null && lesson.getPlanStatus().equals(PlanStatus.NO_PLAN.getValue())) {
            l.setPlanStatus(PlanStatus.PLAN_RUNNING.getValue());
        }
        updateById(l);
    }



    public LearningPlanPageVO queryMyPlans(PageQuery query) {
        LearningPlanPageVO result = new LearningPlanPageVO();
        // 1.获取当前登录用户
        Long userId = UserContext.getUser();
        // 2.获取本周起始时间
        LocalDate now = LocalDate.now();
        LocalDateTime begin = DateUtils.getWeekBeginTime(now);
        LocalDateTime end = DateUtils.getWeekEndTime(now);
        // 3.查询本周计划学习的所有课程，满足三个条件：属于当前用户、有学习计划、学习中
        List<LearningLesson> lessons = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .list();
        if (CollUtils.isEmpty(lessons)) {
            return null;
        }
        // 4.统计当前用户每个课程的已学习小节数量
        List<LearningRecord> learnedRecords = recordMapper.selectList(new QueryWrapper<LearningRecord>().lambda()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .gt(LearningRecord::getFinishTime, begin)
                .lt(LearningRecord::getFinishTime, end)
        );
        Map<Long, Long> countMap = learnedRecords.stream()
                .collect(Collectors.groupingBy(LearningRecord::getLessonId, Collectors.counting()));

        // 5.查询总的统计数据
        // 5.1.本周总的已学习小节数量
        int weekFinished = learnedRecords.size();
        result.setWeekFinished(weekFinished);
        // 5.2.本周总的计划学习小节数量
        int weekTotalPlan = lessons.stream().mapToInt(LearningLesson::getWeekFreq).sum();
        result.setWeekTotalPlan(weekTotalPlan);
        // TODO 5.3.本周学习积分

        // 6.处理分页数据
        // 6.1.分页查询课表信息以及学习计划信息
        Page<LearningLesson> p = new Page<>(query.getPageNo(), query.getPageSize(), lessons.size());
        List<LearningLesson> records = CollUtils.sub(lessons, query.from(), query.from() + query.getPageSize());
        if (CollUtils.isEmpty(records)) {
            return result;
        }
        // 6.2.查询课表对应的课程信息
        Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
        // 6.3.组装数据VO
        List<LearningPlanVO> voList = new ArrayList<>(records.size());
        for (LearningLesson r : records) {
            // 6.4.1.拷贝基础属性到vo
            LearningPlanVO vo = BeanUtils.copyBean(r, LearningPlanVO.class);
            // 6.4.2.填充课程详细信息
            CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());
            if (cInfo != null) {
                vo.setCourseName(cInfo.getName());
                vo.setSections(cInfo.getSectionNum());
            }
            // 6.4.3.每个课程的本周已学习小节数量
            vo.setWeekLearnedSections(countMap.getOrDefault(r.getId(), 0L).intValue());
            voList.add(vo);
        }
        return result.pageInfo(p.getTotal(), p.getPages(), voList);
    }

    private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
        // 3.1.获取课程id
        Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        // 3.2.查询课程信息
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
        if (CollUtils.isEmpty(cInfoList)) {
            // 课程不存在，无法添加
            throw new BadRequestException("课程信息不存在！");
        }
        // 3.3.把课程集合处理成Map，key是courseId，值是course本身
        Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        return cMap;
    }


    private LambdaQueryWrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
        LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
                .lambda()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);
        return queryWrapper;
    }





    private Map<Long, CourseSimpleInfoDTO> queryCourseInfoAnd2Map(List<LearningLesson> records) {
        //3.1、收集当前页面的所有课程ID集合
       // Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        Set<Long> courseIds = CollStreamUtil.toSet(records, LearningLesson::getCourseId);
        //3.2、发起远程调用
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);

        //3.3、健壮性判断
        if(ObjectUtil.isEmpty(courseInfoList)){
            throw new BizIllegalException("课程信息不存在，无法查询我的课表");
        }
        //3.4、将list转换为 map，供后续步骤使用
      /*  Map<Long, CourseSimpleInfoDTO> couseInfoMap = courseInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));*/

        Map<Long, CourseSimpleInfoDTO> couseInfoMap = CollStreamUtil.toIdentityMap(courseInfoList, CourseSimpleInfoDTO::getId);
        return couseInfoMap;
    }

}
